<?php
/*
 * Copyright (c) 2008 Sergey Bondari, bondari@bondari.net
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

namespace Mosaic\System;


/**
 * Resource base class
 *
 * Resources that are handled or required by components.
 * It can be a class, file to include, event, tile etc.
 *
 * @package System
 * @subpackage Resources
 */
abstract class ResourceInfo implements ifResourceInfo {
	/**
	 * Unique resource indentificator
	 * @var string
	 */
	private $key;

	/**
	 * Resource type URN
	 * @var string
	 */
	protected $systemID;

	/**
	 * Array of component information object instances that provide this resource.
	 * @var array
	 */
	protected $provided;


	/**
	 * Array of component information object instances that require this resource.
	 * @var array
	 */
	protected $required;
	

	/**
	 * Resource type URN getter
	 * @return string Resource type URN
	 */
	public function getType() {
		return $this->systemID;
	}


	/**
	 * Resource information instance created
	 *
	 * This method is called from component broker during manifests parsing. Throws kernel exception when resource type is unknown.
	 *
	 * @param string Resource URN
	 * @param data Resource node data
	 */
	static function create($type, $data) {
		switch ($type) {
			case 'mosaic:resource:event':
				return new EventResourceInfo($type, $data['name']);
			break;

			case 'mosaic:resource:tile':
				return new TileResourceInfo($type, $data['name']);
			break;

			case 'mosaic:resource:class':
				return new ClassResourceInfo($type, $data['name'], isset($data['filename']) ? $data['filename'] : $data['skeleton'], isset($data['filename']) ? null : $data['stub'] );
			break;

			case 'mosaic:resource:include':
				return new IncludeResourceInfo($type, $data['filename']);
			break;

			case 'mosaic:resource:kmodule':
				return new KModuleResourceInfo($type, $data['name']);
			break;

		}

		throw new KernelException('Unknown resource type \''.$type.'\'');
	}



	/**
	 * Unique key generator for this resource instance inside the node
	 *
	 * Simply concatenates resource type URN with main type specific data, such as filename, event name, class name etc.
	 *
	 * @return string resource node key
	 */
	static public function createKey($type) {
		switch ($type) {
			case 'mosaic:resource:event':
			case 'mosaic:resource:class':
			case 'mosaic:resource:include':
			case 'mosaic:resource:tile':
			case 'mosaic:resource:kmodule':
				return implode(':', func_get_args());
			break;
		}

		throw new KernelException('Unknown resource type \''.$type.'\'');
	}


	/**
	 * Adds information about providing component
	 *
	 * @param string Component ID
	 * @param ComponentInfo Component information
	 * @return void
	 */
	public function addProvidingComponent($componentID, ComponentInfo $componentInfo) {
		if (isset($this->provided[$componentID])) throw new RuntimeException('Component ID: '.$componentID.' has already manifested iself as a providing component. Ambigious component ID.');
		$this->provided[$componentID] = $componentInfo;
	}

	/**
	 * Adds information about requiring component
	 *
	 * @param string Component ID
	 * @param ComponentInfo Component information
	 * @return void
	 */
	public function addRequiringComponent($componentID, ComponentInfo $componentInfo) {
		if (isset($this->provided[$componentID])) throw new RuntimeException('Component ID: '.$componentID.' has already manifested iself as a requiring component. Ambigious component ID.');
		$this->required[$componentID] = $componentInfo;
	}

	/**
	 * Providing components getter
	 *
	 * @return array
	 */
	public function getProvidingComponents() {
		return $this->provided;
	}

	/**
	 * Requiring components getter
	 *
	 * @return array
	 */
	public function getRequiringComponents() {
		return $this->required;
	}

	/**
	 * Unique key getter
	 *
	 * @return string
	 */
	public final function key() {
		return isset($this->key) ? $this->key : ($this->key = $this->calcKey());
	}

}


